
import config from 'config';
import schema from 'async-validator';
import { AppContext } from 'ROOT/interface/App';
import * as AutoOrderHistoryService from './AutoOrderHistory.service';
import { traderRobot } from 'ROOT/TraderRobot';
import { isObjectLike } from 'lodash';
import AutoOrderHistoryEntity from './AutoOrderHistory.entity';
import SymbolOrderConfigService from "../symbol-order-config/SymbolOrderConfig.service";
import TradeAccountService from '../trade-account/TradeAccount.service';
import { OrderBook, parserBaseSymbol, parserQuoteSymbol } from 'ROOT/trader';
import { binanceCommon } from 'ROOT/binance/BinanceCommon';
import { outLogger } from 'ROOT/common/logger';
import { autoToFixed } from 'ROOT/utils';

export default class AutoOrderController {
  public static index = async (ctx: AppContext) => {
    const { id, current, pageSize } = ctx.request.query;
    const userId = ctx.state.user && ctx.state.user.id;
    if (!userId) {
      ctx.sendError({ message: "未登录，trader获取失败" });
      return;
    }

    try {
      const res = await AutoOrderHistoryService.find({ userid: userId }, { current: Number(current), pageSize: Number(pageSize) });
      ctx.sendSuccess({ data: res });
    } catch (error) {
      ctx.sendError({ message: error });
    }
  }

  /**
   * 获取订单状态并更新
   */
  public static getStatusWithUpdate = async (ctx: AppContext) => {
    const data = ctx.request.body as Record<string, any>;
    const validator = new schema({
      ids: {
        type: "array",
      },
    });
    try {
      await validator.validate(data);
    } catch ({ errors, fields }) {
      ctx.sendError({ errors });
      return;
    }
    const userId = ctx.state.user.id;
    const userTrader = traderRobot.trader.findUserTrader(userId);
    if (!userTrader) {
      ctx.sendError({ message: "未登录，trader获取失败" });
      return;
    }
    try {
      const promiseList: Promise<AutoOrderHistoryEntity>[] = [];
      data.ids.forEach((id) => {
        promiseList.push(AutoOrderHistoryService.findOne({ id: id }));
      })
      const historys = await Promise.all(promiseList);
      for (let i = 0; i < historys.length; i++) {
        const order = historys[i];
        const data = await userTrader.getOrder(order);
        if (isObjectLike(data) && data.status) {
          const avgPrice = (data as any).avgPrice ? Number((data as any).avgPrice) : Number(data.price);
          order.status = data.status;
          if (avgPrice != 0) {
            order.price = avgPrice ? avgPrice : Number(data.price)
          }
          await AutoOrderHistoryService.updateOne(
            { id: order.id },
            order
          );
        }
      }
      ctx.sendSuccess({
        data: historys
      });
    } catch (error) {
      ctx.sendError({ message: error });
    }
  }

  /**
   * 更新或者新建
   */
  public static cancelOrder = async (ctx: AppContext) => {
    const data = ctx.request.body as Record<string, any>;
    const validator = new schema({
      symbol: {
        type: "string",
        required: true,
      },
      id: {
        type: "number",
        required: true,
      },
    });
    try {
      await validator.validate(data);
    } catch ({ errors, fields }) {
      ctx.sendError({ errors });
      return;
    }
    const userId = ctx.state.user && ctx.state.user.id;
    if (!userId) {
      ctx.sendError({ message: "未登录，trader获取失败" });
      return;
    }

    try {
      const userTrader = traderRobot.trader.findUserTrader(userId);
      if (!userTrader) {
        ctx.sendError({
          message: `${userId}不存在`
        });
        return
      }
      const order = await AutoOrderHistoryService.findOne({ id: data.id });
      if (!order) {
        ctx.sendError({
          message: `${data.id}不存在`
        });
        return
      }
      const cancelData = await userTrader.cancelOrder(data.symbol, order.order_id, order.trade_type);
      if (cancelData.message) {
        ctx.sendError({
          message: cancelData.message
        });
        return
      }

      if (isObjectLike(cancelData) && cancelData.status) {
        order.status = cancelData.status;
        await AutoOrderHistoryService.updateOne(
          { id: data.id },
          order
        );
      }
      ctx.sendSuccess({
        data: cancelData
      });
    } catch (error) {
      ctx.sendError({ message: error });
    }
  }

  public static getBeforeOrderConfig = async (ctx: AppContext) => {
    const query = ctx.request.query as Record<string, any>;
    const validator = new schema({
      symbol: {
        type: "string",
        required: true
      },
      tradeType: {
        type: "string",
        required: true
      },
      orderType: {
        type: "string",
        required: true
      },
      depthRangeDis: {
        type: "number",
      },
    });
    if (query.depthRangeDis) {
      query.depthRangeDis = Number(query.depthRangeDis)
    }
    try {
      await validator.validate({symbol: query.symbol, tradeType: query.tradeType, orderType: query.orderType, depthRangeDis: query.depthRangeDis});
    } catch ({ errors, fields }) {
      ctx.sendError({ errors });
      return;
    }
    const userId = ctx.state.user.id;
    try {
      const exchangeAccount = await TradeAccountService.findOne({ userid: userId }, false)
      if (exchangeAccount.exchange === 'binance') {
        const userTrader = traderRobot.trader.findUserTrader(userId);
        if (!userTrader) {
          ctx.sendError({ message: `trader.findUserTrader(${userId})` });
          return;
        }
        if (query.tradeType === 'spot') {
          const pricePoolFormDepth = userTrader.dataHander.orderBook.getTracePrice(query.symbol, query.depthRangeDis);
           const balanceMap = await userTrader.getBalance();
           const base = parserBaseSymbol(query.symbol);
           const quote = parserQuoteSymbol(query.symbol);
          return ctx.sendSuccess({
            data: {
              buy: {
                price: pricePoolFormDepth.buy[pricePoolFormDepth.buy.length - 1],
                free: balanceMap[base].free,
              },
              sell: {
                price: pricePoolFormDepth.sell[pricePoolFormDepth.sell.length - 1],
                free: balanceMap[quote].free
              },
              currentPrice: userTrader.dataHander.orderBook.getCurrentPrice(query.symbol),
            }
          });
        } else if (query.tradeType === 'futures') {
          const pricePoolFormDepth = userTrader.dataHander.futruesOrderBook.getTracePrice(query.symbol, query.depthRangeDis);
          const balanceMap = await userTrader.getFuturesBalance();
          const price = await binanceCommon.getFuturesPrice(query.symbol);
          const base = parserBaseSymbol(query.symbol);
          const quote = parserQuoteSymbol(query.symbol);

          const margin = price / query.lever_rate

          const maxAmount = autoToFixed((balanceMap[quote].availableBalance * query.lever_rate) / (price + margin))
          return ctx.sendSuccess({
            data: {
              buy: {
                price: pricePoolFormDepth.buy[pricePoolFormDepth.buy.length - 1],
              },
              sell: {
                price: pricePoolFormDepth.sell[pricePoolFormDepth.sell.length - 1],
              },
              maxAmount,
              currentPrice: price
            }
          });
        }  else if (query.tradeType === 'delivery') {
          const symbolInfo = await binanceCommon.getDeliverySymolInfo(query.symbol);
          const [deliveryBalance, price] = await Promise.all([
            userTrader.getDeliveryBalance(parserBaseSymbol(query.symbol)),
            binanceCommon.getDeliveryPrice(symbolInfo.symbol)
          ]);
          outLogger.info(`delivery symbolInfo.symbol`, symbolInfo.symbol, deliveryBalance )

          const margin = price / query.lever_rate

          const maxAmount = autoToFixed(((deliveryBalance as any).availableBalance * price * query.lever_rate) / (price + margin))
          const dis = (query.depthRangeDis || 0.2) / 2
          return ctx.sendSuccess({
            data: {
              buy: {
                price: autoToFixed(price * (1 - dis))
              },
              sell: {
                price: autoToFixed(price * (1 + dis))
              },
              maxAmount,
              currentPrice: price
            }
          });
        }
      } else {
        return ctx.sendError({ message: '交易所不支持' });
      }

    } catch (error) {
      ctx.sendError({ message: error });
    }
  }

  /**
   * 删除单个
   */
  public static removeOne = async (ctx: AppContext) => {
    const data = ctx.request.body;
    try {
      // const res = await AutoOrderHistoryService.deleteOne({id: data._id});
      // ctx.sendSuccess({
      //     data: res
      // });
    } catch (error) {
      ctx.sendError({ message: error });
    }
  }


}


